home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 January: Mac OS SDK / Dev.CD Jan 00 SDK1.toast / Development Kits / Mac OS / Multiprocessing 2.0 SDK / Sample Code / CloseViewMP ƒ / µApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-03  |  27.5 KB  |  1,089 lines  |  [TEXT/CWIE]

  1. /**\
  2. |**|    µApp.c
  3. \**/
  4.  
  5. /**\
  6. |**| ==============================================================================
  7. |**| COMPILER DIRECTIVES
  8. |**| ==============================================================================
  9. \**/
  10.  
  11. #define kMaxTasks 64
  12.  
  13. #define SystemSevenOrLater        1
  14. #define DEBUGSTRINGS 1
  15.  
  16. /**\
  17. |**| ==============================================================================
  18. |**| INCLUDES
  19. |**| ==============================================================================
  20. \**/
  21.  
  22. #ifndef USE_PRECOMPILED_HEADER
  23. #include "myHeaders.i"
  24. #endif
  25.  
  26. #include <Devices.h>
  27. #include <Fonts.h>
  28. #include <CodeFragments.h>
  29. #include <Dialogs.h>
  30. #include <DiskInit.h>
  31. #include <LowMem.h>
  32. #include <Sound.h>
  33. #include <Traps.h>
  34. #include <Threads.h>
  35.  
  36. #include <fp.h>
  37. #include <PLStringFuncs.h>
  38.  
  39. #include <stdio.h>
  40. #include <string.h>
  41.  
  42. #if __profile__
  43. #include <Profiler.h>
  44. #endif
  45.  
  46. #include "CloseViewMP.h"
  47.  
  48. /**\
  49. |**| ==============================================================================
  50. |**| TYPEDEFS, STRUCTS, DEFINES, ENUMS, ETC.
  51. |**| ==============================================================================
  52. \**/
  53.  
  54. #if DEBUGSTRINGS
  55. #    define DEBUGSTR(x) DebugStr((x))
  56. #    define LOGSTRING(b,s) if (b) do {DEBUGSTR(s);} while (false);
  57. #else
  58. #    define DEBUGSTR(x)
  59. #    define LOGSTRING(b,s)
  60. #endif
  61.  
  62. #define RECT_WIDTH(r) ((r).right - (r).left)
  63. #define RECT_HEIGHT(r) ((r).bottom - (r).top)
  64.  
  65. #ifndef MIN
  66. #    define ABS(x)    ((x) >= 0 ? (x) : -(x))
  67. #    define MIN(a,b) ((a) < (b) ? (a) : (b))
  68. #    define MAX(a,b) ((a) > (b) ? (a) : (b))
  69. #    define PIN(a,b,c) MIN(MAX((a),(b)),(c))
  70. #endif
  71.  
  72. /**\
  73. |**| ==============================================================================
  74. |**| EXTERNAL FUNCTION PROTOTYPES
  75. |**| ==============================================================================
  76. \**/
  77.  
  78. /**\
  79. |**| ==============================================================================
  80. |**| PRIVATE FUNCTION PROTOTYPES
  81. |**| ==============================================================================
  82. \**/
  83.  
  84. static OSErr Init_Mac(void);
  85. static void Handle_Command(SInt32 ms);
  86. static void Handle_Event(const EventRecord *pEventPtr);
  87. static void Handle_NullEvent(const EventRecord *pEventPtr);
  88. static void Handle_MouseEvent(const EventRecord *pEventPtr);
  89. static void Handle_KeyEvent(char key,SInt16 modifiers);
  90. static void Handle_UpdateEvent(WindowPtr updateWindowP);
  91. static void Handle_ActivateEvent(WindowPtr updateWindowP);
  92. static void Handle_DiskEvent(SInt32 message);
  93. static void Handle_OSEvent(const EventRecord *pEventPtr);
  94. static void Handle_ContentClick(WindowPtr pWindowPtr,const EventRecord *pEventPtr);
  95.  
  96. static Boolean SetUp_MenuBar(void);
  97. static void Adjust_MenuItems(void);
  98.  
  99. static void DoZoomWindow(WindowPtr pWindowPtr, short zoomDir, short hMax, short vMax);
  100. static void DoGrowWindowGrid(WindowPtr pWindowPtr);
  101. static void DoDragWindowGrid(WindowPtr pWindowPtr, Point pPoint);
  102.  
  103. /**\
  104. |**| ==============================================================================
  105. |**| PRIVATE GLOBALS
  106. |**| ==============================================================================
  107. \**/
  108.  
  109. WindowPtr    gWindowPtr = nil;
  110. Rect        gWindowRect;
  111. Boolean        gInBackGround = false;
  112. //Rect         gMenuRect = {0,0,0,0};
  113. static Boolean gQuitFlag = false;
  114.  
  115. static const RGBColor
  116.                 blackRGBColor    = {0x0000,0x0000,0x0000}, 
  117.                 blueRGBColor    = {0x0000,0x0000,0xFFFF},
  118.                 ltBlueRGBColor    = {0x7FFF,0x7FFF,0xFFFF},
  119.                 dkBlueRGBColor    = {0x0000,0x0000,0x7FFF},
  120.                 redRGBColor        = {0xFFFF,0x0000,0x0000},
  121.                 greenRGBColor    = {0x0000,0xFFFF,0x0000},
  122.                 yellowRGBColor    = {0xFFFF,0xFFFF,0x0000},
  123.                 dkGrayRGBColor    = {0x4444,0x4444,0x4444},
  124.                 whiteRGBColor    = {0xFFFF,0xFFFF,0xFFFF};
  125.  
  126. static RgnHandle gMouseRgnHdl = nil;
  127.  
  128. static EventRecord    gTheEvent;                        // from the main event loop
  129. static Boolean        gHasColorQD = true;
  130. static Point        gGridSize = {8,4};
  131.  
  132. /**\
  133. |**| ==============================================================================
  134. |**| PRIVATE FUNCTIONS
  135. |**| ==============================================================================
  136. \**/
  137.  
  138. void main(void)
  139. {
  140. #if __profile__
  141.     if (!ProfilerInit(collectDetailed,bestTimeBase,20,5))
  142.     {
  143. #endif
  144.  
  145.     if (!Init_Mac() && SetUp_MenuBar() && !CVMP_Init(1))
  146.     {
  147.         do
  148.         {
  149.             if (gMouseRgnHdl == nil)
  150.             {
  151.                 Rect tRect = {-1,-1,1,1};
  152.  
  153.                 gMouseRgnHdl = NewRgn();
  154.                 RectRgn(gMouseRgnHdl,&tRect);
  155.             }
  156.  
  157.             InitCursor();
  158.             WaitNextEvent(everyEvent,&gTheEvent,GetCaretTime(),gMouseRgnHdl);
  159.             Handle_Event(&gTheEvent);
  160.         }
  161.         while (!gQuitFlag);
  162.  
  163.         CVMP_Term();
  164.     }
  165. #if __profile__
  166.     }
  167.     ProfilerDump("\pµApp.dump");
  168.     ProfilerTerm();
  169. #endif
  170. }
  171.  
  172. /**\
  173. |**|    Initialize toolboxes
  174. \**/
  175.  
  176. static OSErr Init_Mac(void)
  177. {
  178.     OSErr        error;
  179.     SysEnvRec    theWorld;
  180.         
  181.     //
  182.     //    Test the computer to be sure we can do color.  
  183.     //    If not we would crash, which would be bad.  
  184.     //    If we can’t run, just beep and exit.
  185.     //
  186.  
  187.     error = SysEnvirons(1, &theWorld);
  188.     if (theWorld.hasColorQD == false)
  189.     {
  190.         SysBeep(50);
  191.         ExitToShell();                    // If no color QD, we must leave.
  192.     }
  193.     
  194.     MaxApplZone();
  195.     InitGraf(&(qd.thePort));
  196.     InitFonts();
  197.     InitWindows();
  198.     InitMenus();
  199.     TEInit();
  200.     InitDialogs(nil);
  201.  
  202.     InitContextualMenus();
  203.  
  204.     //
  205.     //    Make a new window for drawing in, and it must be a color window.  
  206.     //    The window is full screen size, made smaller to make it more visible.
  207.     //
  208.  
  209.     gWindowRect = qd.screenBits.bounds;
  210.     gWindowRect.top += LMGetMBarHeight() + 1;
  211.  
  212.     // make it 100x100
  213.     InsetRect(&gWindowRect,
  214.         (gWindowRect.right - gWindowRect.left - 100) >> 1,
  215.         (gWindowRect.bottom - gWindowRect.top - 100) >> 1);
  216.  
  217.     gWindowPtr = NewCWindow(nil, &gWindowRect, "\pCloseViewMP!", true, zoomDocProc, 
  218.                         (WindowPtr) -1, true, 0);
  219.  
  220.     if (gWindowPtr)
  221.         gWindowRect = (*((WindowPeek) gWindowPtr)->contRgn)->rgnBBox;
  222.  
  223.     SetPort(gWindowPtr);                    // set window to current graf port
  224.     TextSize(kTextSize);                    // smaller font for drawing.
  225.  
  226.     {
  227.         short familyID;
  228.         GetFNum("\pMonaco",&familyID);
  229.         TextFont(familyID);
  230.     }
  231.  
  232.     return noErr;
  233. }
  234.  
  235. /**\
  236. |**|    Menu hooks
  237. \**/
  238. #ifdef HellFrozenOver
  239. static pascal short MyMBarHook(Rect *menuRect)
  240. {
  241. //    RgnHandle tempRgn = NewRgn();
  242.  
  243.     gMenuRect = *menuRect;
  244.  
  245. //    RectRgn(tempRgn,menuRect);
  246. //    CalcVisBehind(LMGetWindowList(),tempRgn);
  247. //    InvertRgn(tempRgn);
  248.  
  249.     //YieldToAnyThread();
  250. //    DisposeRgn(tempRgn);
  251.     return 0;
  252. }
  253.  
  254. static pascal void MyMenuHook(void)
  255. {    
  256. //    RgnHandle tempRgn = NewRgn();
  257. //    RectRgn(tempRgn,&gMenuRect);
  258. //    CalcVisBehind(LMGetWindowList(),tempRgn);
  259. //    InvertRgn(tempRgn);
  260.  
  261.     //YieldToAnyThread();
  262. //    DisposeRgn(tempRgn);
  263. }
  264. #endif HellFrozenOver
  265.  
  266. /**\
  267. |**|    Setup menu bar
  268. \**/
  269.  
  270. static Boolean SetUp_MenuBar(void)
  271. {
  272.     Handle mBar = GetNewMBar(128);    // handle to menu bar resource
  273.     Boolean result = false;
  274.  
  275.     if (!ResError() && mBar)
  276.     {
  277.         SetMenuBar(mBar);
  278.         AppendResMenu(GetMenuHandle(mAppleMenu),'DRVR');
  279.         DrawMenuBar();
  280.         ReleaseResource(mBar);
  281.         Adjust_MenuItems();
  282.  
  283. //        LMSetMBarHook(NewMBarHookProc(MyMBarHook));
  284. //        LMSetMenuHook(NewMenuHookProc(MyMenuHook));
  285.  
  286.         result = true;
  287.     }
  288.     return result;
  289. }
  290.  
  291. /**\
  292. |**|    Adjust menu items
  293. \**/
  294.  
  295. static void Adjust_MenuItems(void)
  296. {
  297.     MenuHandle tMenuHdl = GetMenuHandle(mMagMenu);
  298.     if (tMenuHdl)
  299.     {
  300.         UInt16 index,count = CountMItems(tMenuHdl);
  301.         for (index = 1;index <= count;index++)
  302.             CheckItem(tMenuHdl, index, index == gMag);
  303.     }
  304. }
  305.  
  306. /**\
  307. |**|    handle menu command
  308. \**/
  309.  
  310. static void Handle_Command(SInt32 ms)
  311. {
  312.     short    menuID = ms >> 16,
  313.             menuItem = ms & 0xFFFF;
  314.  
  315.     switch (menuID)
  316.     {
  317.         case    mAppleMenu:
  318.             switch (menuItem)
  319.             {
  320.                 case iAboutBox:        // Bring up alert for About.
  321.                     SysBeep(15);
  322.                     break;
  323.                 default:            // All non-About items in this menu are DAs.
  324.                     {
  325.                         Str255    daName;
  326.                         GetMenuItemText(GetMenuHandle(menuID),menuItem,daName);
  327.                         OpenDeskAcc(daName);
  328.                     }
  329.                     break;
  330.             }
  331.             break;
  332.         case    mFileMenu:
  333.             switch (menuItem)
  334.             {
  335.                 case iQuit:
  336.                     gQuitFlag = true;
  337.                     break;
  338.                 default:
  339.                     SysBeep(15);
  340.                     break;
  341.             }
  342.             break;
  343.         case    mMagMenu:
  344.             CVMP_SetMag(menuItem);
  345.             break;
  346.         case    mWeightMenu:        // Weight Menu
  347.             CVMP_SetWeight(menuItem);
  348.             break;
  349.     }
  350. }
  351.  
  352. /**\
  353. |**|    handle event
  354. \**/
  355.  
  356. static void Handle_Event(const EventRecord *pEventPtr)
  357. {
  358.     switch (pEventPtr->what)
  359.     {
  360.         case nullEvent:        // 0
  361.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, nullEvent.;g");
  362.             Handle_NullEvent(pEventPtr);
  363.             break;
  364.         case mouseDown:        // 1
  365.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, mouseDown.;g");
  366.             Handle_MouseEvent(pEventPtr);
  367.             break;
  368.         case mouseUp:        // 2
  369.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, mouseUp.;g");
  370.             break;
  371.         case keyDown:        // 3
  372.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, keyDown.;g");
  373.             goto dokey;
  374.         case keyUp:            // 4
  375.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, keyUp.;g");
  376.             break;
  377.         case autoKey:        // 5
  378.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, autoKey.;g");
  379. dokey:
  380.             Handle_KeyEvent((char)(pEventPtr->message & charCodeMask),pEventPtr->modifiers);
  381.         case updateEvt:        // 6
  382.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, updateEvt.;g");
  383.             Handle_UpdateEvent((WindowPtr)pEventPtr->message);
  384.             break;
  385.         case diskEvt:        // 7
  386.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, diskEvt.;g");
  387.             Handle_DiskEvent(pEventPtr->message);
  388.             break;
  389.         case activateEvt:    // 8
  390.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, activateEvt.;g");
  391.             Handle_ActivateEvent((WindowPtr) pEventPtr->message);
  392.             break;
  393.         case osEvt:            // 15
  394.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, osEvt.;g");
  395.             Handle_OSEvent(pEventPtr);
  396.             break;
  397.         case kHighLevelEvent:    // 23
  398.             LOGSTRING(0,"\p|pHandle_Event-I-Debug, kHighLevelEvent.;g");
  399.             AEProcessAppleEvent(pEventPtr);
  400.             break;
  401.         default:
  402.             DEBUGSTR("\p|pHandle_Event-I-Debug, UnHandled Event.;g");
  403.             break;
  404.     }
  405. }
  406.  
  407. /**\
  408. |**|    handle null event
  409. \**/
  410.  
  411. static void Handle_NullEvent(const EventRecord *pEventPtr)
  412. {
  413.     (pEventPtr);    // #pragma unused (pEventPtr)
  414.     if (gWindowPtr)
  415.     {
  416.         Rect    tRect = {40,20,52,128};
  417.         const RGBColor blackRGBColor = {0,0,0}, yellowRGBColor = {255,255,0};
  418.         GrafPtr savePort;
  419.  
  420.         GetPort(&savePort);
  421.         SetPort(gWindowPtr);
  422.  
  423.         gWindowRect = (*((WindowPeek) gWindowPtr)->contRgn)->rgnBBox;
  424.  
  425.         CVMP_DoNull();
  426.  
  427.         SetPort(savePort);
  428.     }
  429. }
  430.  
  431. /**\
  432. |**|    handle mousedown event
  433. \**/
  434.  
  435. static void Handle_MouseEvent(const EventRecord *pEventPtr)
  436. {
  437.     WindowPtr            window;
  438.     short                part;
  439.  
  440.     CVMP_Update();            // Force a demand refresh to give that smooth look.
  441.  
  442.     part = FindWindow(pEventPtr->where,&window);
  443.  
  444.     if (part != inContent)
  445.         SetCursor(&qd.arrow);
  446.  
  447.     switch(part)
  448.     {
  449.         case inContent:
  450.             Handle_ContentClick(window,pEventPtr);
  451.             break;
  452.  
  453.         case inDrag:
  454.             CVMP_Pause(true);
  455.             DoDragWindowGrid(window, pEventPtr->where);
  456.             break;
  457.  
  458.         case inGoAway:
  459.             if (TrackGoAway(window,pEventPtr->where))
  460.             {
  461.                 CVMP_Pause(true);
  462.                 DisposeWindow(window);
  463.                 if (window == gWindowPtr)
  464.                     gWindowPtr = nil;
  465.             }
  466.             break;
  467.  
  468.         case inGrow:
  469.                 CVMP_Pause(true);
  470.                 DoGrowWindowGrid(window);
  471.             break;
  472.  
  473.         case inMenuBar:        // Process mouse menu command (if any).
  474.             {
  475.                 SInt32 ms;
  476.  
  477.                 Adjust_MenuItems();
  478.                 ms = MenuSelect(pEventPtr->where);
  479.                 if (ms)
  480.                     Handle_Command(ms);
  481.                 HiliteMenu(0);        // Unhighlight what MenuSelect hilited.
  482.             }
  483.             break;
  484.  
  485.         case inSysWindow:    // Let the system handle the mouseDown.
  486.             SystemClick(pEventPtr,window);
  487.             break;
  488.  
  489.         case inZoomIn:
  490.         case inZoomOut:
  491.             {
  492.                 Rect zoomLimits = qd.screenBits.bounds;
  493.  
  494.                 CVMP_Pause(true);
  495.                 DoZoomWindow(window, part,
  496.                     RECT_WIDTH(zoomLimits),
  497.                     RECT_HEIGHT(zoomLimits));
  498.             }
  499.             break;
  500.  
  501.         default:
  502.             break;
  503.     }
  504.     if (gWindowPtr)
  505.         gWindowRect = (*((WindowPeek) gWindowPtr)->contRgn)->rgnBBox;
  506.  
  507. //    SetRect(&gMenuRect, 0, 0, 0, 0);
  508. }
  509.  
  510. /**\
  511. |**|    handle key events
  512. \**/
  513.  
  514. static void Handle_KeyEvent(char key,SInt16 modifiers)
  515. {
  516.     if ((modifiers & cmdKey) != 0)
  517.     {
  518.         Adjust_MenuItems();
  519.         Handle_Command(MenuKey(key));
  520.         HiliteMenu(0);        // Unhighlight what MenuSelect hilited.
  521.     }
  522. }
  523.  
  524. /**\
  525. |**|    handle update events
  526. \**/
  527.  
  528. static void Handle_UpdateEvent(WindowPtr updateWindowP)
  529. {
  530.     GrafPtr savePort;
  531.  
  532.     GetPort(&savePort);
  533.     SetPort(updateWindowP);
  534.     BeginUpdate(updateWindowP);
  535.  
  536.     if (updateWindowP == gWindowPtr)
  537.     {
  538.  
  539.     }
  540. #ifdef HellFrozenOver
  541.     DrawControls(updateWindowP);
  542. #else
  543.     UpdateControls(updateWindowP,updateWindowP->visRgn);
  544. #endif
  545.     DrawGrowIcon(updateWindowP);
  546.     EndUpdate(updateWindowP);
  547.  
  548.     SetPort(savePort);
  549. }
  550.  
  551. /**\
  552. |**|    handle disk events
  553. \**/
  554.  
  555. static void Handle_DiskEvent(SInt32 message)
  556. {
  557.     Point dialogLocation = {100,100};
  558.  
  559.     if ((message & 0xFFFF0000) != noErr)
  560.     {
  561.         DIBadMount(dialogLocation,message);
  562.     }
  563. }
  564.  
  565. /**\
  566. |**|    handle Activate events
  567. \**/
  568.  
  569. static void Handle_ActivateEvent(WindowPtr updateWindowP)
  570. {
  571. #pragma unused(updateWindowP)
  572. }
  573.  
  574. /**\
  575. |**|    handle OS events
  576. \**/
  577.  
  578. static void Handle_OSEvent(const EventRecord *pEventPtr)
  579. {
  580.     UInt32 message = pEventPtr->message;
  581.     if ((message >> 24) == suspendResumeMessage)
  582.     {
  583.         LOGSTRING(0,"\p|Handle_OSEvent-I-Debug, suspendResumeMessage.;g");
  584.         if ((message & resumeFlag) != 0)
  585.             gInBackGround = false;
  586.         else
  587.             gInBackGround = true;
  588.     }
  589.     else if ((message >> 24) == mouseMovedMessage)
  590.     {
  591.         Rect tRect = {-1,-1,1,1};
  592.  
  593.         LOGSTRING(0,"\p|Handle_OSEvent-I-Debug, mouseMovedMessage.;g");
  594.  
  595.         OffsetRect(&tRect,pEventPtr->where.h,pEventPtr->where.v);
  596.         RectRgn(gMouseRgnHdl,&tRect);
  597.         CVMP_SetMidPoint(pEventPtr->where);
  598.         CVMP_Update();        // Tickle the blit task.
  599.     }
  600. }
  601.  
  602. /**\
  603. |**|    handle mouse down in window content
  604. \**/
  605.  
  606. static void Handle_ContentClick(WindowPtr pWindowPtr,const EventRecord *pEventPtr)
  607. {
  608. #pragma unused (pEventPtr)
  609.     if (pWindowPtr != FrontWindow())
  610.         SelectWindow(pWindowPtr);
  611.     else
  612.         CVMP_DoClick(pEventPtr);
  613. }
  614.  
  615. /**\
  616. |**|    return the rectangle for the screen that contains the most of the rectangle
  617. \**/
  618.  
  619. static Rect GetMajorScreenRect(Rect *pRectPtr)
  620. {
  621.     Rect        result;
  622.     GDHandle    dominantGDevice = nil;
  623.  
  624.     /*
  625.      *    Color QuickDraw implies the possibility of multiple monitors. 
  626.      *  One should move the rect onto the monitor containing the greatest
  627.      *    portion of the rect. This requires walking the gDevice list.
  628.      */
  629.  
  630.     if (gHasColorQD)
  631.     {
  632.         Rect                theSect;
  633.         GDHandle            nthDevice;
  634.         long                sectArea, greatestArea;
  635.  
  636.         greatestArea = 0;
  637.         for (nthDevice = DMGetFirstScreenDevice(true);nthDevice;
  638.             nthDevice = DMGetNextScreenDevice(nthDevice,true))
  639.         {
  640.             SectRect(pRectPtr, &(**nthDevice).gdRect, &theSect);
  641.             sectArea = (long) RECT_WIDTH(theSect) * (long) RECT_HEIGHT(theSect);
  642.             if (sectArea > greatestArea) {
  643.                 greatestArea = sectArea;        // save the greatest intersection
  644.                 dominantGDevice = nthDevice;    // and which device it belongs to
  645.             }
  646.         }
  647.     }
  648.  
  649.     /*
  650.      *    At this point, we know the dimensions of our rectangle, and we know
  651.      *    what screen we're going to put it on. To be more specific, however, we need a
  652.      *    rectangle which defines the maximum dimensions of the rectangle.
  653.      *
  654.      *    This rectangle accounts for the thickness of the window frame, the menu bar, and
  655.      *    one or two pixels around the edges for cosmetic reasons.
  656.      */
  657.  
  658.     if (dominantGDevice != nil)
  659.     {
  660.         result = (**dominantGDevice).gdRect;
  661.         if (dominantGDevice == GetMainDevice())        // account for menu bar on main device
  662.             result.top += GetMBarHeight();
  663.     }
  664.     else
  665.     {
  666.         result = qd.screenBits.bounds;                // if no gDevice, use default monitor
  667.         result.top += GetMBarHeight();
  668.     }
  669.  
  670.     return result;
  671. }
  672.  
  673. /**\
  674. |**|    Pin the first rect into the second
  675. \**/
  676.  
  677. static void PinRectInRect(Rect *pRect1,const Rect *pRect2)
  678. {
  679.     if (pRect1->left < pRect2->left)
  680.     {
  681.         OffsetRect(pRect1,pRect2->left - pRect1->left,0);
  682.         if (pRect1->right > pRect2->right)
  683.             pRect1->right = pRect2->right;
  684.     }
  685.     else if (pRect1->right > pRect2->right)
  686.     {
  687.         OffsetRect(pRect1,pRect2->right - pRect1->right,0);
  688.         if (pRect1->left < pRect2->left)
  689.             pRect1->left = pRect2->left;
  690.     }
  691.  
  692.     if (pRect1->top < pRect2->top)
  693.     {
  694.         OffsetRect(pRect1,0,pRect2->top - pRect1->top);
  695.         if (pRect1->bottom > pRect2->bottom)
  696.             pRect1->bottom = pRect2->bottom;
  697.     }
  698.     else if (pRect1->bottom > pRect2->bottom)
  699.     {
  700.         OffsetRect(pRect1,0,pRect2->bottom - pRect1->bottom);
  701.         if (pRect1->top < pRect2->top)
  702.             pRect1->top = pRect2->top;
  703.     }
  704. }
  705.  
  706. /**\
  707. |**|    DoZoomWindow
  708. \**/
  709.  
  710. static void DoZoomWindow(WindowPtr pWindowPtr, short zoomDir, short hMax, short vMax)
  711. {
  712.     Rect                *zoomRect;
  713.     Rect                globalPortRect, dGDRect;
  714.  
  715.     if (TrackBox(pWindowPtr, gTheEvent.where, zoomDir))
  716.     {
  717.         SetPort(pWindowPtr);
  718.         EraseRect(&pWindowPtr->portRect);    // recommended for cosmetic reasons
  719.  
  720.         if (zoomDir == inZoomOut)
  721.         {
  722.             /*
  723.              *    ZoomWindow() is a good basic tool, but it doesn't do everything necessary to
  724.              *    implement a good human interface when zooming. In fact it's not even close for
  725.              *    more high-end hardware configurations. We must help it along by calculating an
  726.              *    appropriate window size and location any time a window zooms out.
  727.              */
  728.  
  729.             zoomRect = &(*((WindowPeek) pWindowPtr)->strucRgn)->rgnBBox;
  730.             dGDRect = GetMajorScreenRect(zoomRect);
  731.  
  732.             globalPortRect = pWindowPtr->portRect;
  733.             LocalToGlobal(&topLeft(globalPortRect));        // calculate the window's portRect
  734.             LocalToGlobal(&botRight(globalPortRect));        // in global coordinates
  735.  
  736.             // account for the window frame and inset it a few pixels
  737.             dGDRect.left    += 2 + globalPortRect.left - zoomRect->left;
  738.             dGDRect.top        += 2 + globalPortRect.top - zoomRect->top;
  739.             dGDRect.right    -= 1 + zoomRect->right - globalPortRect.right;
  740.             dGDRect.bottom    -= 1 + zoomRect->bottom - globalPortRect.bottom;
  741.  
  742.             /*
  743.              *    Now we know exactly what our limits are, and since there are input parameters
  744.              *    specifying the dimensions we'd like to see, we can move and resize the zoom
  745.              *    state rectangle for the best possible results. We have three goals in this:
  746.              *    1. Display the window entirely visible on a single device.
  747.              *    2. Resize the window to best represent the dimensions of the document itself.
  748.              *    3. Move the window as short a distance as possible to achieve #1 and #2.
  749.              */
  750.  
  751.             zoomRect = &(**(WStateDataHandle) ((WindowPeek) pWindowPtr)->dataHandle).stdState;
  752.  
  753.             /*
  754.              *    Initially set the zoom rectangle to the size requested by the input parameters,
  755.              *    although not smaller than a minimum size. We do this without moving the origin.
  756.              */
  757.  
  758.             zoomRect->right = (zoomRect->left = globalPortRect.left) + hMax;
  759. //                                    MAX(hMax, MinWindowWidth(pWindowPtr));
  760.             zoomRect->bottom = (zoomRect->top = globalPortRect.top) + vMax;
  761. //                                    MAX(vMax, MinWindowHeight(pWindowPtr));
  762.  
  763.             // Shift the entire rectangle if necessary to bring its origin inside dGDRect.
  764.             OffsetRect(zoomRect,
  765.                         MAX(dGDRect.left - zoomRect->left, 0),
  766.                         MAX(dGDRect.top - zoomRect->top, 0));
  767.  
  768.             /*
  769.              *    Shift the rectangle up and/or to the left if necessary to accomodate the view,
  770.              *    and if it is possible to do so. The rectangle may not be moved such that its
  771.              *    origin would fall outside of dGDRect.
  772.              */
  773.  
  774.             OffsetRect(zoomRect,
  775.                         -PIN(zoomRect->right - dGDRect.right, 0, zoomRect->left - dGDRect.left),
  776.                         -PIN(zoomRect->bottom - dGDRect.bottom, 0, zoomRect->top - dGDRect.top));
  777.  
  778.             // Clip expansion to dGDRect, in case view is larger than dGDRect.
  779.             zoomRect->right = MIN(zoomRect->right, dGDRect.right);
  780.             zoomRect->bottom = MIN(zoomRect->bottom, dGDRect.bottom);
  781.         }
  782.         ZoomWindow(pWindowPtr, zoomDir, false);        // all it needed was a brain transplant
  783.     }
  784. }    // DoZoomWindow
  785.  
  786. /**\
  787. |**|    DoGrowWindowGrid
  788. \**/
  789.  
  790. #define kExtremeNeg -32768
  791. #define kExtremePos (32767 - 1) /* required to address an old region bug, see develop 20 Q&As */
  792.  
  793. static void PullRect(Rect* startRect);    // prototype
  794. static void DoGrowWindowGrid(WindowPtr pWindowPtr)
  795. {
  796.     PenState oldPen;
  797.     WindowPtr tempWP, WMPort;
  798.     Rect draggingRect = pWindowPtr->portRect;
  799.     Rect wideOpen =    {kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos};
  800.     RgnHandle oldRgn = NewRgn();
  801.  
  802.     GetPort(&tempWP);
  803.     SetPort(pWindowPtr);
  804.  
  805.     /* normalize my rectangle into the window manager port coordinates */
  806.     LocalToGlobal((Point *) &draggingRect.top);
  807.     LocalToGlobal((Point *) &draggingRect.bottom);
  808.  
  809.     /*  go to the WManager port */
  810.     GetWMgrPort(&WMPort);
  811.     SetPort(WMPort);
  812.  
  813.     /* save the Window manager pen state since we'll be changing it */
  814.     GetPenState(&oldPen);
  815.  
  816.     /* localize back */
  817.     GlobalToLocal((Point *) &draggingRect.top);
  818.     GlobalToLocal((Point *) &draggingRect.bottom);
  819.  
  820.     /* save the current clip region, and set our wide-open clip */
  821.     GetClip(oldRgn);
  822.     ClipRect(&wideOpen);
  823.  
  824.     /* go to the routine below to do the actual dragging */
  825.     PullRect(&draggingRect);
  826.  
  827.     /* restore the original environment */
  828.     SetClip(oldRgn);
  829.     SetPenState(&oldPen);
  830.     DisposeRgn(oldRgn);
  831.  
  832.     /* now size the window for the returned rect */
  833.     SetPort(pWindowPtr);
  834.     InvalRect(&pWindowPtr->portRect);
  835.  
  836.     {
  837.         Rect tRect = GetMajorScreenRect(&(*((WindowPeek) pWindowPtr)->contRgn)->rgnBBox);
  838.         PinRectInRect(&draggingRect,&tRect);
  839.         MoveWindow(pWindowPtr,draggingRect.left,draggingRect.top,true);
  840.     }
  841.  
  842.     SizeWindow(pWindowPtr, draggingRect.right - draggingRect.left, draggingRect.bottom - draggingRect.top, true);
  843.     SetPort(tempWP);
  844. }    // DoGrowWindowGrid
  845.  
  846. static void PullRect(Rect* startRect)
  847. {
  848.     Rect oldRect;
  849.     Point endPoint;
  850.     Boolean hreversed = false;
  851.     Boolean vreversed = false;
  852.     short tempH,tempV;
  853.     short divByGridh,divByGridv;
  854.  
  855.     /* set up */
  856.     oldRect = *startRect;
  857.     PenMode(srcXor);                            /* So we can rubberband */
  858.     PenPat(&qd.gray);
  859.     FrameRect(startRect);
  860.     divByGridh = startRect->right;
  861.     divByGridv = startRect->bottom;
  862.  
  863.     while (StillDown())
  864.     {    /* Keep doing this as long as the */
  865.         /* user keeps the mouse down */
  866.  
  867.         GetMouse(&endPoint);                    /* Current mouse position in local */
  868.  
  869.         // see if it's on a  grid point
  870.         tempH = ABS(endPoint.h - divByGridh) / gGridSize.h;
  871.         tempV = ABS(endPoint.v - divByGridv) / gGridSize.v;
  872.  
  873.         // normalize to our grid values. We'll always go outwards as better
  874.         if ((tempH * gGridSize.h) != ABS(endPoint.h - divByGridh))    // shove out based on the remainer
  875.             endPoint.h = (((endPoint.h) / gGridSize.h) * gGridSize.h) + gGridSize.h;
  876.         if ((tempV * gGridSize.v) != ABS(endPoint.v - divByGridv))
  877.             endPoint.v = (((endPoint.v) / gGridSize.v) * gGridSize.v) + gGridSize.v;
  878.  
  879.         // If things reversed, we have to make sure that we don't try
  880.         // and grid the origin point of the drag, cuz that would be weird
  881.         if (hreversed)
  882.         {    /* see if the rectangle flipped first */
  883.             if (endPoint.h > startRect->right)    /* they flipped back */
  884.                 hreversed = false;                /* and ignore this move */
  885.             else    /* still reversed */
  886.                 startRect->left = endPoint.h;
  887.         }
  888.         else
  889.         {
  890.             if (endPoint.h < startRect->left)
  891.                 hreversed = true;
  892.             else
  893.                 startRect->right = endPoint.h;
  894.         }
  895.         if (vreversed)
  896.         {    /* see if it flipped first */
  897.             if (endPoint.v > startRect->bottom)    /* they flipped back */
  898.                 vreversed = false;                /* and ignore this move */
  899.             else                /* still reversed */
  900.                 startRect->top = endPoint.v;
  901.         }
  902.         else
  903.         {
  904.             if (endPoint.v < startRect->top)
  905.                 vreversed = true;
  906.             else
  907.                 startRect->bottom = endPoint.v;
  908.         }
  909.         
  910.         if (!EqualRect(startRect,&oldRect))
  911.         {    /* redraw the rect only if the mouse moved */
  912.             FrameRect(&oldRect);
  913.             FrameRect(startRect);                /* draw the new rect */
  914.             oldRect = *startRect;
  915.         }
  916.     }
  917.     FrameRect(startRect);
  918.  
  919.     PenMode(srcCopy);
  920.     PenPat(&qd.black);
  921. }    // PullRect
  922.  
  923.  
  924. /*-------------------------------------------------------------------------------------
  925.  
  926.     DoDragWindowGrid- a big nasty function to Drag a window along grid lines.  
  927.     Note the elegant error handling.  You should change it to make your users happy.
  928.     
  929.     You can change the size of the 'grid rects' by changing the value of kIncrement.
  930.     
  931. */
  932. static void DoDragWindowGrid(WindowPtr pWindowPtr, Point pPoint)
  933. {
  934.     RgnHandle    dragRgn, lastDragRgn, insetGray;
  935.     GrafPtr        oldPort, tmpPort;
  936.     Point        currPt, firstMulPoint, lastMulPoint, currMulPoint;
  937.     Boolean        frameHidden;
  938.     enum        {kIncrement = 16, kBorderInset = 4};
  939.  
  940.     // Set up our regions - init our variables.
  941.     dragRgn = NewRgn(); 
  942.     lastDragRgn = NewRgn(); 
  943.     insetGray = NewRgn();
  944.     if ((dragRgn == NULL) || (lastDragRgn == NULL) || (insetGray == NULL)) {
  945.         DebugStr("\pnot enough memory- bye!");
  946.         return;
  947.     }
  948.     CopyRgn(GetGrayRgn(), insetGray);
  949.     if (MemError() != noErr) {
  950.         DebugStr("\pnot enough memory- bye!");
  951.         return;
  952.     }
  953.  
  954.     InsetRgn(insetGray, kBorderInset, kBorderInset);
  955.     frameHidden = false;
  956.  
  957.     // Set up a port to draw into, and save off the old
  958.     tmpPort = (GrafPtr)NewPtr(sizeof(GrafPort));
  959.     if (tmpPort == NULL) {
  960.         DebugStr("\pnot enough memory- bye!");
  961.         return;
  962.     }
  963.     GetPort(&oldPort);
  964.     OpenPort(tmpPort);
  965.     CopyRgn(GetGrayRgn(), tmpPort->visRgn);
  966.     if (MemError() != noErr) {
  967.         DebugStr("\pnot enough memory- bye!");
  968.         return;
  969.     }
  970.     tmpPort->portRect = (*GetGrayRgn())->rgnBBox;
  971.     SetPort(tmpPort);
  972.     
  973.     PenMode(patXor);
  974.     PenPat(&qd.gray);
  975.  
  976.     // Set the incoming point to be on a multiple of kIncrement,
  977.     // to make later calculations easier.
  978.     currMulPoint.h = pPoint.h + (kIncrement/2);
  979.     currMulPoint.h /= kIncrement; currMulPoint.h *= kIncrement;
  980.     currMulPoint.v = pPoint.v + (kIncrement/2);
  981.     currMulPoint.v /= kIncrement; currMulPoint.v *= kIncrement;
  982.  
  983.     firstMulPoint = lastMulPoint = currMulPoint;
  984.  
  985.     CopyRgn(((WindowPeek)pWindowPtr)->strucRgn, dragRgn);
  986.     if (MemError() != noErr) {
  987.         DebugStr("\pnot enough memory- bye!");
  988.         return;
  989.     }
  990.  
  991.     CopyRgn(((WindowPeek)pWindowPtr)->strucRgn, lastDragRgn);
  992.     if (MemError() != noErr) {
  993.         DebugStr("\pnot enough memory- bye!");
  994.         return;
  995.     }
  996.  
  997.     // Draw the first framed region, which will follow the mouse
  998.     // on the screen
  999.     FrameRgn(lastDragRgn);
  1000.  
  1001.     while (WaitMouseUp() == true) {
  1002.         // Now track the mouse, and when it moves enough make the framed
  1003.         // region move as well.
  1004.         GetMouse(&currPt);
  1005.     
  1006.         // Set the new point to be on a multiple of kIncrement
  1007.         currMulPoint.h = currPt.h + (kIncrement/2);
  1008.         currMulPoint.h /= kIncrement; currMulPoint.h *= kIncrement;
  1009.         currMulPoint.v = currPt.v + (kIncrement/2);
  1010.         currMulPoint.v /= kIncrement; currMulPoint.v *= kIncrement;
  1011.  
  1012.         // Should we be showing the frame region ??
  1013.         if (PtInRgn(currPt, insetGray) == false) {
  1014.             // It's somewhere near the edges, so hide the frame
  1015.             if (frameHidden == false)    // if it's not hidden already, hide it now
  1016.                 FrameRgn(lastDragRgn);
  1017.             frameHidden = true;
  1018.         }
  1019.         else {    // else, the frame should be shown if it's hidden
  1020.             if (frameHidden == true) {
  1021.                 FrameRgn(lastDragRgn);
  1022.                 frameHidden = false;
  1023.             }
  1024.         }
  1025.     
  1026.         // Has the mouse moved ?
  1027.         if (!EqualPt(currMulPoint,lastMulPoint)) {
  1028.             // The mouse coordinates have changed enough to adjust the window,
  1029.             // so move the frame accordingly
  1030.             OffsetRgn(dragRgn, currMulPoint.h - lastMulPoint.h, currMulPoint.v - lastMulPoint.v);
  1031.  
  1032.             if (frameHidden == false) {
  1033.                 // Only show the frame if we're allowed to.
  1034.                 FrameRgn(dragRgn);        
  1035.                 FrameRgn(lastDragRgn);
  1036.             }
  1037.             lastMulPoint = currMulPoint;
  1038.             CopyRgn(dragRgn, lastDragRgn);
  1039.             if (MemError() != noErr) {
  1040.                 DebugStr("\pnot enough memory- bye!");
  1041.                 return;
  1042.             }
  1043.         }    
  1044.     }
  1045.     
  1046.     // If frameHidden is true, there's no need to erase the final frame.
  1047.     if (frameHidden == false)
  1048.         FrameRgn(lastDragRgn);
  1049.  
  1050.     if (!EqualPt(lastMulPoint,firstMulPoint) && (frameHidden == false)) {
  1051.         // The mouse has moved from its original position and is
  1052.         // somewhere on the screen, so move the window accordingly.
  1053.         Point    globalPt, diffPt, contPt = {0, 0};
  1054.  
  1055.         // Calculate the difference between the strucRgn's 0, 0 and
  1056.         // the window's content region 0, 0.  Remember that MoveWindow
  1057.         // moves the window's *content* to the coordinate specified, and
  1058.         // we want to move the window's structure to fit in the lastDragRgn
  1059.         SetPort(pWindowPtr);
  1060.         // LocalToGlobal works much better when the port is set up...
  1061.         LocalToGlobal(&contPt);
  1062.         SetPort(tmpPort);
  1063.         diffPt.h = contPt.h - (*((WindowPeek)pWindowPtr)->strucRgn)->rgnBBox.left;
  1064.         diffPt.v = contPt.v - (*((WindowPeek)pWindowPtr)->strucRgn)->rgnBBox.top;
  1065.         
  1066.         globalPt.h = (*lastDragRgn)->rgnBBox.left;
  1067.         globalPt.v = (*lastDragRgn)->rgnBBox.top;
  1068.         LocalToGlobal(&globalPt);
  1069.         globalPt.h += diffPt.h;
  1070.         globalPt.v += diffPt.v;
  1071.         MoveWindow(pWindowPtr, globalPt.h, globalPt.v, true);
  1072.     }
  1073.  
  1074.     {
  1075.         Rect wRect = (*((WindowPeek) pWindowPtr)->contRgn)->rgnBBox;
  1076.         Rect tRect = GetMajorScreenRect(&wRect);
  1077.         PinRectInRect(&wRect,&tRect);
  1078.         MoveWindow(pWindowPtr,wRect.left,wRect.top,true);
  1079. //        SizeWindow(pWindowPtr, wRect.right - wRect.left, wRect.bottom - wRect.top, true);
  1080.     }
  1081.  
  1082.     // Close the port and tear everything down
  1083.     ClosePort(tmpPort);
  1084.     SetPort(oldPort);
  1085.     DisposeRgn(dragRgn);
  1086.     DisposeRgn(insetGray);
  1087.     DisposeRgn(lastDragRgn);
  1088. }    // DoDragWindowGrid
  1089.